﻿namespace CSP.Applications

module Queens =

    let private makeConstraint i j =
        let d = j - i
        fun x y ->  x <> y && x - d <> y && x + d <> y
    
    /// Creates the queens problem of given size.
    let queens n =
        let domains =
            let domain = CSP.Domain.ofSeq [1 .. n]
            [1 .. n] |> List.map (fun i -> (i, domain)) |> Map.ofList
        let constraints =
            let indices = [ for i in 1 .. (n - 1) do
                            for j in (i + 1) .. n do
                            yield (i, j) ]
            indices |> List.map (fun (i,j) -> (i, makeConstraint i j, j))
        CSP.Problem.create domains constraints

    let private transform n = fun s -> [1 .. n] |> List.map (fun i -> Map.find i s)

    /// Finds all solutions of the queens problem of given size.
    let solve n = queens n |> CSP.Solving.simpleSolve |> Seq.map (transform n)

    /// Finds one solution of the queens problem of given size.
    let find n = queens n |> CSP.Solving.simpleFind |> Option.map (transform n)
